import { Context, Schema, Logger, h } from "koishi";
import { OpenAI } from "openai";
import getToolList from "./toolList";
import axios from "axios";
import { URL } from "url";
import { existsSync } from "fs";
import { join } from "path";

export const name = "mcpo";

export interface Config {
  baseURl: string;
  model: string;
  token: string;
  mcpoUrl: string;
  mcpoKey: string;
}

export const Config: Schema<Config> = Schema.object({
  baseURl: Schema.string()
    .default("https://api.siliconflow.cn/v1")
    .description("base URL"),

  model: Schema.string()
    .default("Qwen/Qwen2.5-72B-Instruct")
    .description("model"),

  token: Schema.string().default("").description("token"),

  mcpoUrl: Schema.string()
    .default("http://127.0.0.1:8000")
    .description("mcpo URL"),
  mcpoKey: Schema.string().default("").description("mcpo api-Key"),
});

const logger = new Logger("mcpo");

export async function apply(ctx: Context, config: Config) {
  axios.defaults.baseURL = config.mcpoUrl;
  const toolList = await getToolList(config.mcpoUrl);
  logger.info("mcpo toolList", toolList);
  const openai = new OpenAI({
    apiKey: config.token,
    baseURL: config.baseURl,
  });

  ctx
    .command("mcpo <text:text>", "mcpo")
    .example("mcpo 你好")
    .action(async ({ session }, text) => {
      let messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [];
      messages.push({
        role: "user",
        content: text,
      });
      const response = await openai.chat.completions.create({
        model: config.model,
        messages,
        tools: toolList,
        tool_choice: "auto",
      });
      messages.push(response.choices[0].message);
      if (
        !response.choices[0].message.tool_calls ||
        response.choices[0].message.tool_calls.length === 0
      ) {
        return response.choices[0].message.content;
      }
      if (response.choices[0].message.tool_calls) {
        for (const tool of response.choices[0].message.tool_calls) {
          logger.info(
            "mcpo Tool call:",
            "/" + tool.function.name.replace(".", "/"),
            tool
          );
          try {
            const content = await axios
              .post(
                "/" + tool.function.name.replace(".", "/"),
                JSON.parse(tool.function.arguments),
                {
                  headers: {
                    Authorization: "Bearer " + config.mcpoKey,
                  },
                }
              )
              .then((res) => res.data);

            messages.push({
              role: "tool",
              content:
                typeof content === "string" ? content : JSON.stringify(content),
              tool_call_id: tool.id,
            });
          } catch (error) {
            logger.error("mcpo error:", error);
            return (
              `调用 ${tool.function.name.replace(
                ".",
                "/"
              )} 失败, mcpo error: ` + error.message
            );
          }
        }
      }

      const finalResponse = await openai.chat.completions.create({
        model: config.model,
        messages,
      });

      //  提取图片链接
      const imgRegex = /!\[.*?\]\((.*?)\)/g;
      const imgMatches =
        finalResponse.choices[0].message.content.match(imgRegex);
      logger.info("mcpo imgMatches:", imgMatches);
      if (imgMatches) {
        for (const imgMatch of imgMatches) {
          const imgUrl = imgMatch.match(/\((.*?)\)/)![1];
          // logger.info("mcpo imgUrl:", imgUrl);
          // 判断是不是url
          const url = new URL(imgUrl);
          // logger.info("mcpo url:", url);
          if (
            url.protocol === "http:" ||
            url.protocol === "https:" ||
            url.protocol === "file:"
          ) {
            await session.send(h("image", { src: imgUrl }));
          } else if (existsSync(join(url.protocol, url.pathname))) {
            logger.info("mcpo imgUrl:", imgUrl);
            await session.send(h("image", { src: "file://" + imgUrl }));
          } else {
            logger.info("mcpo imgUrl:", imgUrl);
            await session.send(h("image", { src: imgUrl }));
          }
        }
      }
      return finalResponse.choices[0].message.content;
    });
}
